﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MaasOne.Finance;
using MaasOne.RSS;

namespace Tos2Google
{
    public static class Decision
    {
        enum NowIs { Premarket, Market, OtherTime }

        public static Signal Make(FullData data, HistQuotesDataChain history, Feed news, List<Bar> Bars10min, List<Bar> Bars1min)
        {
            // where are we in time?
            DateTime newYorkTime = MainForm2.StaticThis.ServerNow();
            DateTime today = new DateTime(newYorkTime.Year, newYorkTime.Month, newYorkTime.Day);
            DateTime yesterday = today.AddDays(-1);
            var premarketStart = new TimeSpan(8, 0, 0); // 08:00
            var marketStart = new TimeSpan(9, 30, 0);   // 09:30
            var marketStop = new TimeSpan(16, 0, 0);    // 16:00
            var nowIs = NowIs.OtherTime;
            if (newYorkTime.TimeOfDay >= premarketStart && newYorkTime.TimeOfDay <= marketStop)
            {
                if (newYorkTime.TimeOfDay < marketStart)
                    nowIs = NowIs.Premarket;
                else
                    nowIs = NowIs.Market;
            }
            if (nowIs == NowIs.OtherTime)
                return null; // no market nor premarket - not much point to continue (?)

            // prepare what we usually need (modify as wished)
            var bars_10min = Bars10min.Where(bar => bar.StartTime.DayOfYear > yesterday.DayOfYear);
            var bars_1min = Bars1min.Where(bar => bar.StartTime.DayOfYear > yesterday.DayOfYear);
            if (bars_10min.Count() == 0 && bars_1min.Count() == 0)
                return null; // no bar data at all (should not happen)
            var last5_days = history.Take(5);
            var last10_days = history.Take(10);
            var last30_days = history.Take(30);
            var premarketBars_10min = bars_10min.Where(bar => bar.StartTime.TimeOfDay >= premarketStart && bar.StartTime.TimeOfDay < marketStart);
            var premarketBars_1min = bars_10min.Where(bar => bar.StartTime.TimeOfDay >= premarketStart && bar.StartTime.TimeOfDay < marketStart);
            var marketBars_10min = bars_10min.Where(bar => bar.StartTime.TimeOfDay >= marketStart);
            var marketBars_1min = bars_10min.Where(bar => bar.StartTime.TimeOfDay >= marketStart);
            var last5minutes = bars_1min.Where(bar => bar.StartTime >= newYorkTime.AddMinutes(-5));

            // 5-day flat? lowest?  (do in similar against last10_days and/or last30_days)
            double last5daysHigh = last5_days.Max(day => day.High);
            double last5daysLow = last5_days.Min(day => day.Low);
            double last5daysMedium = (last5daysHigh + last5daysLow) / 2.0;
            double last5daysPriceFluctuationPercent = (last5daysHigh - last5daysLow) * 100.0 / last5daysMedium;
            bool last5daysFlat = last5daysPriceFluctuationPercent <= 1.3; // % of price fluctuation allowed
            bool last5daysLow_isNow = (double)data.Last <= last5daysLow;

            // today's low?
            bool? todaysLowest_isNow;
            var useForToday = Bars10min; // OR premarketBars_10min OR marketBars_10min
            if (useForToday.Count() == 0)
                useForToday = Bars1min; // no 10-min bars (yet), try 1-min ones
            if (useForToday.Count() > 0) // just to be sure there is some data
            {
                double todaysLow = useForToday.Min(bar => Math.Min(bar.Open, bar.Close));
                //double todaysHigh = useForToday.Max(bar => Math.Max(bar.Open, bar.Close));
                todaysLowest_isNow = (double)data.Last <= todaysLow;
            }
            // use like: if (todaysLowest_isNow.HasValue && todaysLowest_isNow.Value == true) ...

            // quickLow?
            bool? quickLow = null;
            if (last5minutes.Count() > 0)
            {
                double last5minutesHigh = last5minutes.Max(bar => Math.Max(bar.Open, bar.Close));
                double last5minutesLow = last5minutes.Min(bar => Math.Min(bar.Open, bar.Close));
                double last5minutesMedium = (last5minutesHigh + last5minutesLow) / 2.0;
                double last5minutesPriceFluctuationPercent = (last5minutesHigh - last5minutesLow) * 100.0 / last5minutesMedium;
                if (last5minutesPriceFluctuationPercent >= 0.7) // % of price fluctuation required (in last 5 minutes)
                {
                    // fluctuation is big enough, now check are we in the low-area
                    double aboveLowestInFluctuationPercent = ((double)data.Last - last5minutesLow) * 100.0 / (last5minutesHigh - last5minutesLow);
                    quickLow = aboveLowestInFluctuationPercent <= 10.0; // in which lowest % of the 5-min fluctuation we must be (negative also makes it)
                }
            }
            // use like: if (quickLow.HasValue && quickLow.Value == true) ...

            // news (just an example of how to read them)
            var lastWeekNews = news.Items.Where(n => n.PublishDate > DateTime.Today.AddDays(-8));
            bool lastWeekHadGoodNews = lastWeekNews.Where(n => n.Title.Contains("rises")).Count() > 0;

            /* ... we have TOS DDE data in "data", can be used like below
            if (data.MarketCap > 1.1M && data.PercentChange < 1.3M) // MarketCap is in millions
                return new SellSignal();
            if (data.Last > data.Low52)
                return new BuySignal();
            if (data.Low < data.Open)
                return new SellSignal(); */

            return new BuySignal(); // for now (debug-phase)
        }
    }
}
